import WebSocket from 'ws';
import { generateSign, getTimestamp } from './auth';
import { CONFIG } from '../utils/config';
import { WsResponse, LoginRequest, WsRequest, SubscriptionArgs } from './types';

export class WSClient {
  private socket: WebSocket | null = null;
  private reconnectTimer: NodeJS.Timeout | null = null;
  private heartbeatInterval: NodeJS.Timeout | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  private messageHandlers: Map<string, Function[]> = new Map();
  private isLoggedIn = false;
  private connectionPromise: Promise<void> | null = null;
  private loginPromise: Promise<void> | null = null;

  constructor(private wsUrl: string = CONFIG.WS_URL) { }

  public connect(): Promise<void> {
    // 如果已经有一个连接请求在进行中，直接返回该Promise
    if (this.connectionPromise && this.socket && this.socket.readyState === WebSocket.CONNECTING) {
      return this.connectionPromise;
    }

    this.connectionPromise = new Promise((resolve, reject) => {
      if (!this.wsUrl) {
        reject(new Error("WebSocket URL is undefined."));
        return;
      }

      // 如果已经连接，直接返回
      if (this.socket && this.socket.readyState === WebSocket.OPEN) {
        resolve();
        return;
      }

      // 关闭可能存在的旧连接
      if (this.socket) {
        this.socket.close();
        this.socket = null;
      }

      this.socket = new WebSocket(this.wsUrl);

      // 设置一个超时，如果在指定时间内没有连接成功，则拒绝Promise
      const connectionTimeout = setTimeout(() => {
        reject(new Error("WebSocket connection timeout"));
      }, 15000); // 15秒超时

      // 设置事件监听器
      this.setupEventListeners();

      // 特殊处理open事件，确保只触发一次resolve
      this.socket.once('open', () => {
        clearTimeout(connectionTimeout);
        console.log('✅ WebSocket connected');
        this.reconnectAttempts = 0;
        this.startHeartbeat();
        resolve();
      });

      this.socket.once('error', (err) => {
        clearTimeout(connectionTimeout);
        this.handleError(err);
        reject(err);
      });
    });

    return this.connectionPromise;
  }

  private setupEventListeners() {
    if (!this.socket) {
      throw new Error("WebSocket is not initialized.");
    }

    // 移除之前可能存在的事件监听器，避免重复
    this.socket.removeAllListeners('message');
    this.socket.removeAllListeners('close');

    // 添加新的事件监听器 (不再重复添加open和error，因为在connect方法中已经添加)
    this.socket.on('message', (data) => this.handleMessage(data));
    this.socket.on('close', () => this.handleClose());
  }

  private handleMessage(data: WebSocket.Data) {
    try {
      const response = JSON.parse(data.toString()) as WsResponse;
      // console.log(`📥 Received: ${JSON.stringify(response).substring(0, 200)}${JSON.stringify(response).length > 200 ? '...' : ''}`);
      this.handleResponse(response);
    } catch (err) {
      console.error('❌ Message parsing error:', err);
    }
  }

  private handleError(err: Error) {
    console.error('❌ WebSocket error:', err);
    this.emit('error', err);
  }

  private handleClose() {
    console.log('⚠️ WebSocket disconnected');
    this.isLoggedIn = false;
    this.stopHeartbeat();
    this.scheduleReconnect();
    this.emit('close');
  }

  private startHeartbeat() {
    this.stopHeartbeat(); // 确保之前的心跳被清除
    this.heartbeatInterval = setInterval(() => {
      if (this.socket && this.socket.readyState === WebSocket.OPEN) {
        this.socket.ping();
      }
    }, 30000);
  }

  private stopHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
    }
  }

  public login(): Promise<void> {
    // 如果已经登录，直接返回成功
    if (this.isLoggedIn) {
      return Promise.resolve();
    }

    // 如果已经有登录请求在进行中，直接返回该Promise
    if (this.loginPromise) {
      return this.loginPromise;
    }

    this.loginPromise = new Promise((resolve, reject) => {
      // 确保WebSocket已连接
      if (!this.isConnected()) {
        reject(new Error("Cannot login: WebSocket is not connected"));
        this.loginPromise = null;
        return;
      }

      const timestamp = getTimestamp();
      const sign = generateSign(timestamp, CONFIG.SECRET_KEY);

      const loginRequest: LoginRequest = {
        op: 'login',
        args: [{
          apiKey: CONFIG.API_KEY,
          passphrase: CONFIG.PASSPHRASE,
          timestamp,
          sign
        }]
      };

      // 设置登录超时
      const loginTimeout = setTimeout(() => {
        this.loginPromise = null;
        reject(new Error("Login timeout"));
      }, 15000); // 15秒超时

      // 监听一次性登录成功事件
      const loginSuccessHandler = () => {
        clearTimeout(loginTimeout);
        this.isLoggedIn = true;
        this.loginPromise = null;
        resolve();
      };

      // 监听一次性登录失败事件
      const loginErrorHandler = (err: any) => {
        clearTimeout(loginTimeout);
        this.loginPromise = null;
        reject(err);
      };

      // 使用once确保回调只被调用一次
      this.once('loginSuccess', loginSuccessHandler);
      this.once('loginError', loginErrorHandler);

      console.log('🔑 Sending login request...');
      const sendSuccess = this.send(loginRequest);

      if (!sendSuccess) {
        clearTimeout(loginTimeout);
        this.off('loginSuccess', loginSuccessHandler);
        this.off('loginError', loginErrorHandler);
        this.loginPromise = null;
        reject(new Error("Failed to send login request"));
      }
    });

    return this.loginPromise;
  }

  private handleResponse(response: WsResponse) {
    if (response.event === 'login') {
      if (response.code === '0') {
        console.log(`🎉 Login success! Connection ID: ${response.connId}`);
        this.isLoggedIn = true;
        this.emit('loginSuccess', response);
      } else {
        console.error(`❌ Login failed (Code ${response.code}): ${response.msg}`);
        this.emit('loginError', { code: response.code, message: response.msg });
      }
    } else if (response.event === 'error') {
      console.error(`❌ Operation failed (Code ${response.code}): ${response.msg}`);
      this.emit('error', { code: response.code, message: response.msg });
    } else if (response.arg && response.arg.channel) {
      // 处理所有带instId的频道，统一使用 channel:instId 格式
      if (response.arg.instId) {
        const eventName = `${response.arg.channel}:${response.arg.instId}`;
        this.emit(eventName, response.data);
        // 同时也发送到没有instId的事件通道，保持兼容性
        this.emit(response.arg.channel, response.data);
      } else {
        // 没有instId的频道保持原样
        this.emit(response.arg.channel, response.data);
      }
    } else if (response.event === 'subscribe') {
      console.log(`✅ Successfully subscribed to ${response.arg?.channel}`);
      this.emit('subscribeSuccess', response);
    } else if (response.event === 'unsubscribe') {
      console.log(`✅ Successfully unsubscribed from ${response.arg?.channel}`);
      this.emit('unsubscribeSuccess', response);
    } else {
      // 处理其他类型的响应
      console.log(`📝 Received response: ${JSON.stringify(response).substring(0, 100)}...`);
      // 尝试根据操作类型分发消息
      if (response.id) {
        this.emit(`response:${response.id}`, response);
      }
    }
  }

  private scheduleReconnect() {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error('⛔ Maximum reconnect attempts reached');
      this.emit('reconnectFailed');
      return;
    }

    this.reconnectAttempts++;
    const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);

    console.log(`♻️ Attempting reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${delay}ms...`);

    this.reconnectTimer = setTimeout(() => {
      this.connect().catch(err => {
        console.error('❌ Reconnect failed:', err);
      });
    }, delay);
  }

  public close(disableReconnect: boolean = false) {
    // 清除重连定时器
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    
    // 停止心跳
    this.stopHeartbeat();
    
    // 如果需要禁用重连，设置重连尝试次数为最大值
    if (disableReconnect) {
      this.reconnectAttempts = this.maxReconnectAttempts;
    }
    
    // 关闭WebSocket连接
    if (this.socket) {
      // 移除close事件监听器，避免触发自动重连
      if (disableReconnect) {
        this.socket.removeAllListeners('close');
        // 添加一次性close事件处理，但不触发重连
        this.socket.once('close', () => {
          console.log('🔌 WebSocket connection closed manually');
        });
      }
      
      this.socket.close();
      this.socket = null;
    }
    
    this.isLoggedIn = false;
    this.connectionPromise = null;
    this.loginPromise = null;
  }

  /**
   * 发送JSON消息到WebSocket
   * @param message 要发送的对象
   * @returns 发送是否成功
   */
  public send<T>(message: WsRequest<T> | object): boolean {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      console.log(`📤 Sending: ${JSON.stringify(message).substring(0, 200)}${JSON.stringify(message).length > 200 ? '...' : ''}`);
      this.socket.send(JSON.stringify(message));
      return true;
    } else {
      console.error('❌ Cannot send message: WebSocket is not open.');
      return false;
    }
  }

  /**
   * 订阅一个WebSocket频道
   * @param channel 频道名称，如 "account", "trades"
   * @param instId 可选的交易对ID
   * @param ccy 可选的币种
   * @returns 订阅请求是否成功发送
   */
  public subscribe(channel: string, instId?: string, ccy?: string): boolean {
    const args: SubscriptionArgs[] = [{ channel }];
    if (instId) {
      args[0].instId = instId;
    }
    if (ccy) {
      args[0].ccy = ccy;
    }
    const subscriptionRequest: WsRequest<SubscriptionArgs> = {
      op: 'subscribe',
      args: args
    };
    console.log(`⬆️ Subscribing to ${channel} channel...`);
    return this.send(subscriptionRequest);
  }

  /**
   * 取消订阅一个WebSocket频道
   * @param channel 频道名称
   * @param instId 可选的交易对ID
   * @param ccy 可选的币种
   * @returns 取消订阅请求是否成功发送
   */
  public unsubscribe(channel: string, instId?: string, ccy?: string): boolean {
    const args: SubscriptionArgs[] = [{ channel }];
    if (instId) {
      args[0].instId = instId;
    }
    if (ccy) {
      args[0].ccy = ccy;
    }
    const unsubscribeRequest: WsRequest<SubscriptionArgs> = {
      op: 'unsubscribe',
      args: args
    };
    console.log(`⬇️ Unsubscribing from ${channel} channel...`);
    return this.send(unsubscribeRequest);
  }

  /**
   * 订阅具有特定参数的频道，如指数K线
   * @param channel 频道名称，如 "index-candle30m"
   * @param instId 交易对ID，如 "BTC-USD"
   * @returns 订阅请求是否成功发送
   */
  public subscribeCandle(channel: string, instId: string): boolean {
    const args: SubscriptionArgs[] = [{
      channel: channel,
      instId: instId
    }];

    const subscriptionRequest: WsRequest<SubscriptionArgs> = {
      op: 'subscribe',
      args: args
    };
    console.log(`⬆️ Subscribing to ${channel} channel for ${instId}...`);
    return this.send(subscriptionRequest);
  }

  /**
   * 取消订阅具有特定参数的频道
   * @param channel 频道名称，如 "index-candle30m"
   * @param instId 交易对ID，如 "BTC-USD"
   * @returns 取消订阅请求是否成功发送
   */
  public unsubscribeCandle(channel: string, instId: string): boolean {
    const args: SubscriptionArgs[] = [{
      channel: channel,
      instId: instId
    }];

    const unsubscribeRequest: WsRequest<SubscriptionArgs> = {
      op: 'unsubscribe',
      args: args
    };
    console.log(`⬇️ Unsubscribing from ${channel} channel for ${instId}...`);
    return this.send(unsubscribeRequest);
  }

  /**
   * 注册一个回调函数，用于处理特定频道或事件的消息
   * @param eventName 频道名称或事件名 (如 "loginSuccess", "error", "account")
   * @param callback 处理函数
   */
  public on(eventName: string, callback: Function): void {
    if (!this.messageHandlers.has(eventName)) {
      this.messageHandlers.set(eventName, []);
    }
    this.messageHandlers.get(eventName)?.push(callback);
  }

  /**
   * 注册一个一次性回调函数，在事件触发一次后自动移除
   * @param eventName 事件名称
   * @param callback 回调函数
   */
  public once(eventName: string, callback: Function): void {
    const onceWrapper = (...args: any[]) => {
      this.off(eventName, onceWrapper);
      callback(...args);
    };
    this.on(eventName, onceWrapper);
  }

  /**
   * 移除特定事件的特定回调函数
   * @param eventName 事件名称
   * @param callback 要移除的回调函数，如果不提供则移除该事件的所有回调
   */
  public off(eventName: string, callback?: Function): void {
    if (!callback) {
      // 移除该事件的所有回调
      this.messageHandlers.delete(eventName);
    } else {
      // 移除特定回调
      const handlers = this.messageHandlers.get(eventName);
      if (handlers) {
        const index = handlers.indexOf(callback);
        if (index !== -1) {
          handlers.splice(index, 1);
        }
        if (handlers.length === 0) {
          this.messageHandlers.delete(eventName);
        }
      }
    }
  }

  /**
   * 触发特定事件或频道的回调函数
   * @param eventName 频道名称或事件名
   * @param args 传递给回调函数的参数
   */
  private emit(eventName: string, ...args: any[]): void {
    const handlers = this.messageHandlers.get(eventName);
    if (handlers) {
      [...handlers].forEach(handler => {
        try {
          handler(...args);
        } catch (e) {
          console.error(`❌ Error in handler for ${eventName}:`, e);
        }
      });
    }
  }

  /**
   * 检查WebSocket是否已连接
   */
  public isConnected(): boolean {
    return this.socket !== null && this.socket.readyState === WebSocket.OPEN;
  }

  /**
   * 检查是否已登录
   */
  public checkLoggedIn(): boolean {
    return this.isLoggedIn;
  }

  /**
   * 移除所有指定频道的事件监听器
   * @param eventName 事件名称
   */
  public removeAllListeners(eventName: string): void {
    this.messageHandlers.delete(eventName);
  }
}